/**
 * A simple SMS send and receive demo.
 * 
 * Copyright ?1998-2005 Research In Motion Ltd. 
 */



import net.rim.device.api.ui.*;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.container.*;
import net.rim.device.api.io.*;
import net.rim.device.api.system.*;
import bbdev.resource.*;
import net.rim.device.api.i18n.*;
import javax.microedition.io.*;
import java.util.*;
import java.io.*;
import javax.wireless.messaging.*;

/**
 * <p>A simple demo of SMS send and receive. This program requires an associated server component,  you can find this
 * component at com.rim.samples.server.smsdemo
 * <p>This application makes use of SIGNED APIs and therefore requires signing to function on the device.
 */
public class OpenPop extends UiApplication implements OpenPopResResource
{
    //constants ----------------------------------------------------------------
    private static final int MAX_PHONE_NUMBER_LENGTH = 32;

    //members --------------------------------------------------------------
    private Fetion _fetion;
    private ListeningThread _listener;
    private SendThread _sender;
    private MessageConnection _mc;
    private OpenPopScreen _mainScreen;
    private ReplyScreen _replyScreen;
    private RichTextField _content;
    private Vector _contentOffset;
    private MyContact _contact;
    private MenuItem _replyMenuItem = new MenuItem (_resources,REPLY,90,10) {
         public void run()
         {
              String toAddress=null;
              String toName=null;
              int toPos=0;
              int toIndex=0;
              // todo
              int pos=_content.getCursorPosition();
              int offsetSize=_contentOffset.size();
              for (int i=0;i<offsetSize;++i) {
                    ContentOffset o=(ContentOffset)_contentOffset.elementAt(i);
                    if (pos>=o.from && pos<=o.to) {
                        toName=o.name;
                        toAddress=o.address;
                        toPos=o.to;
                        toIndex=i;
                        break;
                    }
              }
              if (toAddress==null || toName==null) {
                    return;
              } 
              System.out.println(toAddress);
              _replyScreen.setTo(toName,toAddress,toPos,toIndex);
              _replyScreen.display();
         }
    };
    private MenuItem _replyFetionMenuItem = new MenuItem (_resources,REPLY_WITH_FETION,80,10) {
         public void run()
         {
              String toAddress=null;
              String toName=null;
              int toPos=0;
              int toIndex=0;
              // todo
              int pos=_content.getCursorPosition();
              int offsetSize=_contentOffset.size();
              for (int i=0;i<offsetSize;++i) {
                    ContentOffset o=(ContentOffset)_contentOffset.elementAt(i);
                    if (pos>=o.from && pos<=o.to) {
                        toName=o.name;
                        toAddress=o.address;
                        toPos=o.to;
                        toIndex=i;
                        break;
                    }
              }
              if (toAddress==null || toName==null) {
                    return;
              } 
            _fetion.setTo(toName,toAddress,toPos,toIndex);
            _fetion.display();
         }
        
    };
    
    //inner class for offset
    private class ContentOffset {
        public int from;
        public int to;
        public String address;  
        public String name;      
    };
    //inner class for OpenPopScreen
     private class OpenPopScreen extends MainScreen {
                private UiApplication _app;
                public OpenPopScreen (UiApplication uiapp) {
                    super();
                    _app=uiapp;                   
                }
                private MenuItem _syncMenuItem = new MenuItem(_resources, SYNCCONTACT, 100, 10) {
                    public void run()
                    {
                        _contact.syncContact();          
                    }
                };
                private MenuItem _exitMenuItem = new MenuItem(_resources, EXIT, 110, 10) {
                    public void run()
                    {
                        _listener.stop();
                        _sender.stop(); 
                        _fetion.stop();
                        close();                
                    }
                };
                protected void makeMenu(Menu menu, int instance) {
                        menu.add(_replyMenuItem);
                        menu.add(_replyFetionMenuItem);
                        menu.add(_syncMenuItem);
                        menu.add(_exitMenuItem);                       
                }
                public boolean onSavePrompt() {
                        return true;
                }
                public boolean onClose() {
                        _content.setText("");
                        _contentOffset.removeAllElements();                                     
                        requestBackground();
                        return false;
                }
                protected boolean keyChar(char key, int status, int time) {
                        if (key==Characters.LATIN_SMALL_LETTER_R) {
                            _replyFetionMenuItem.run();
                            return true;
                        }
                        if (key==Characters.LATIN_CAPITAL_LETTER_R) {
                            _replyMenuItem.run();
                            return true;
                        }
                        return super.keyChar(key, status, time);
                }
        }

    //statics ------------------------------------------------------------------
    private static ResourceBundle _resources = ResourceBundle.getBundle(BUNDLE_ID,BUNDLE_NAME);
    private static String _openString = "sms://:0"; 

    public static void main(String[] args)
    {
        System.out.println("started");
        new OpenPop().enterEventDispatcher();
    }

    //inner classes ------------------------------------------------------------
    private class ListeningThread extends Thread
    {
        private boolean _stop = false;
        public synchronized void stop()
        {
            _stop = true;
            try {
                _mc.close(); //close the connection so the thread will return.
            } catch (IOException e) {
                System.err.println(e.toString());
            }
        }

        public void run()
        {
            try {
                 System.out.println("about to getting message");
                _mc = (MessageConnection)Connector.open(_openString); //closed by the stop() method
                for(;;)
                {
                    if ( _stop )
                    {
                        return;
                    }
                    System.out.println("getting message");                    
                    Message m = _mc.receive();
                    System.out.println("got message");
                    receivedSmsMessage(m);              
                   
                }
            } catch (IOException e)
            {
                //likely the stream was closed
                System.err.println(e.toString());
            }
        }
    }

    /**
     * a simple abstraction of an sms message, used by the SendThread class
     */
    private static final class SmsMessage
    {
        public String _address;
        public String _msg;

        public SmsMessage(String address, String msg)
        {
            _address = address;
            _msg = msg;
        }
        
       
    }

    /**
     * A thread to manage outbound transactions
     */
    private class SendThread extends Thread
    {
        //members --------------------------------------------------------------
        private static final int TIMEOUT = 500; //ms

        private Vector _msgs = new Vector(5); //a vector of SmsMessage objects - give it an initial capacity of 5 (unlikely that, in this implementation, more than 5 msgs will be queued at any one time)
        
        private volatile boolean _start = false;
        private volatile boolean _stop = false;

        //methods --------------------------------------------------------------
        //requests are queued
        public synchronized void send(String address, String msg)
        {
            _start = true;
            _msgs.addElement(new SmsMessage(address, msg));
        }

        //shutdown the thread
        public synchronized void stop()
        {
            _stop = true;
            //try {
             //   if ( _mc != null ) _mc.close();
           // } catch (IOException e ) {
          //      System.err.println(e.toString());                
          //  }
        }
        void send(SmsMessage sms) {
            System.out.println(sms._address);
            try {
                DatagramConnection smsConnection = (DatagramConnection)Connector.open("sms://"+sms._address);
                SmsAddress destinationAddr = new SmsAddress("//"+sms._address);
                
                SMSPacketHeader header = destinationAddr.getHeader();
                header.setMessageCoding(SMSParameters.MESSAGE_CODING_UCS2);
                
                byte[] data = sms._msg.getBytes("UTF-16BE"); 
                Datagram d = smsConnection.newDatagram(data.length);
                ((DatagramBase)d).setAddressBase(destinationAddr);
                d.setData(data, 0, data.length);
                smsConnection.send(d);
                smsConnection.close();
                System.out.println("done");
            } catch (Exception e) {
                System.out.println(e.toString());
            }
           
        }
        public void run()
        {            
            for(;;)
            {
                //Thread control
                while( !_start && !_stop)
                {
                    //sleep for a bit so we don't spin
                    try {
                        sleep(TIMEOUT);
                    } catch (InterruptedException e) {
                        System.err.println(e.toString());
                    }
                }
                //exit condition
                if ( _stop )
                {
                    return;
                }

                while(true)
                {
                    try {
                        SmsMessage sms = null;
                        synchronized (this)
                        {
                            if ( !_msgs.isEmpty() )
                            {
                                sms = (SmsMessage)_msgs.firstElement();
                                _msgs.removeElement(sms); //remove the element so we don't send it again!
                            }
                            else
                            {
                                _start = false;
                                break;
                            }
                        }
                        
                        //_mc.send(sms.toMessage(_mc));
                        send(sms);

                    } catch (Exception e) {
                        System.err.println(e.toString());                       
                    }
                }
            }
        }
    } 
 
    //constructors -------------------------------------------------------------
    public OpenPop()
    {
        _mainScreen = new OpenPopScreen(this);
        _mainScreen.setTitle(new LabelField("OpenPop", LabelField.USE_ALL_WIDTH));
        _content=new RichTextField();   
        _mainScreen.add(_content); 
        _replyScreen=new ReplyScreen(this);
        _contentOffset=new Vector();
        _fetion=new Fetion(this);
        _listener = new ListeningThread();
        _listener.start();
        _sender = new SendThread();
        _sender.start();
        _contact=new MyContact();
        pushScreen(_mainScreen);
        requestBackground();
    }

    /**
     * Update the GUI with the data just received
     */
   
    private void updateContent(final String msg,final String name,final String address)
    {
        invokeLater(new Runnable() {
            public void run()
            {                    
                String orig=_content.getText();
                _content.setText(orig+msg);
                // update content offset
                ContentOffset offset=new ContentOffset();
                offset.from=orig.length();
                offset.to=offset.from+msg.length()-1;
                offset.address=address;
                offset.name=name;
                _contentOffset.addElement(offset);
            }
        });

    }

    /**
     * some simple formatting for a received sms message
     */
    private void receivedSmsMessage(Message m)
    {
       
        String address = m.getAddress().substring(6);
        System.out.println(address);
        if (address.startsWith("12520")) {//fetion
            address=address.substring(5);
        }
        String msg = null;
        if ( m instanceof TextMessage )
        {
            TextMessage tm = (TextMessage)m;
            msg = tm.getPayloadText();
        }
        StringBuffer sb = new StringBuffer();       
        
        // translate address to name
        // address is 123456...
       
        Vector contacts=_contact.getContacts();
        String name=null;
        String portion=null;
        if (address.length()>11) {
            portion=address.substring(address.length()-11);
        } else {
            portion=address;
        }
        for (int i=0;i<contacts.size();++i) {
            Tuple curr=(Tuple)contacts.elementAt(i);
            for (int j=0;j<curr.phone.length;++j) {
                if (curr.phone[j].endsWith(portion)) {
                    name=curr.name;
                    // todo: maybe use address in contact instead of true address, because fetion address can't be replyed in fetion...
                    break;
                }
            }
            if (name!=null) {
                break;
            }
           
        }
        String realName=null;
        if (name!=null) {
            realName=name;
        } else {
            realName=address;
        }
        sb.append(realName);
        sb.append('\n');        
        sb.append(msg);
        sb.append('\n');

        updateContent(sb.toString(),realName,address);
       
        requestForeground();
       
    }
    public void  updateReply(int toPos,int toIndex,String content) {
        String replyContent="\n  R: "+content;
        String orig=_content.getText();
        String now=orig.substring(0,toPos)+replyContent+orig.substring(toPos);
        _content.setText(now);
        int length=replyContent.length();
        int size=_contentOffset.size();
        for (int i=toIndex+1;i<size;++i) {
            ContentOffset offset=(ContentOffset)_contentOffset.elementAt(i);
            offset.from+=length;
            offset.to+=length;
        }
    }
    public void send(String addr, String data)
    {
        _sender.send(addr, data);
    }
}
